package src.E_Thread;

// 线程同步机制，多个线程操作同个对象
// 不安全线程，示例一（抢票）

// 解决方式：使用线程同步机制，同步代码块(synchronized(同步监视器){代码}) 和 同步方法(方法前面加入synchronized关键字) 和 lock锁，弊端：性能会降低，但是保证了安全
/*  1、lock是显示锁（手动开启和关闭锁），synchronized是隐式锁（出了作用域自动释放）
    2、lock只有代码块锁，synchronized有代码块锁和方法锁
    3、lock锁，jvm将花费较少的时间来调度线程，性能更好，并且具有更好的拓展性（提供更多的子类）
    4、优先使用顺序：lock > 同步代码块（已经进入方法体，分配了相应的资源） > 同步方法（在方法体之外）
*/
public class E15_UnsafeThread01 {
    public static void main(String[] args) {
        ScrambleForTickets sft = new ScrambleForTickets(); // 唯一对象this
        new Thread(sft,"梦梦").start();
        new Thread(sft,"乐乐").start();
        new Thread(sft,"黄牛").start();
    }
}

class ScrambleForTickets implements Runnable{
    private int num = 10;
    @Override
    public void run() {
        // 锁记得要放循环里面，不然就是第一条线程把票拿完了才出来
        while (true){
            // 模拟延时扩大问题客观性，不然cpu一下跑完了看不效果
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 现在是安全线程了（同步代码块，这个参数必须是唯一的对象，也可以用object）
            synchronized (this){
                if (num <= 0) break;
                // 模拟延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName()+" 抢到了第 "+num--+" 张票");
            }
        }
    }
}
